#include <iostream>
#include <functional>
#include <vector>

using std::cout;
using std::endl;
using std::bind;
using std::function;
using std::vector;


int add(int x, int y)
{
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
    return x + y;
}

void test1()
{
    cout << "test1() function" << endl;
    //f1是一个函数对象
    function<int()> f1 = std::bind(add, 1, 2);
    cout << f1() << endl;

    using namespace std::placeholders;
    function<int(int)> f2 = std::bind(add, 1, _1);
    cout << f2(10) << endl;

    function<int(int,int,int)> f3 = std::bind(add, 1, _3);
    cout << f3(10, 20, 30) << endl;
}

struct Foo
{
    int add(int x, int y)
    {
        _data += 10;
        cout << "_data:" << _data << endl;
        cout << "x:" << x << endl;
        cout << "y:" << y << endl;
        return x + y;
    }

    int _data = 100;
};

void test2()
{
    cout << "test2() function" << endl;
    Foo foo;
    //使用std::bind时，如果绑定的是非静态的成员函数，则必须要
    //在成员函数名之前加上&符号
    function<int()> f1 = std::bind(&Foo::add, &foo, 1, 2);
    cout << f1() << endl << endl;

    using namespace std::placeholders;
    function<int(int)> f2 = std::bind(&Foo::add, &foo, 1, _1);
    cout << f2(10) << endl << endl;

    function<int(int,int)> f3 = std::bind(&Foo::add, &foo, 1, _2);
    cout << f3(10, 20) << endl << endl;

    function<int(int,int)> f4 = std::bind(&Foo::add, &foo, _2, _1);
    cout << f4(10, 20) << endl << endl;

    //绑定了一个数据成员
    function<int()> f5 = std::bind(&Foo::_data, &foo);
    cout << f5() << endl;
}

void test3()
{
    cout << "test3()" << endl;
    Foo foo;
    //使用std::bind时，如果绑定的是非静态的成员函数，则必须要
    //在成员函数名之前加上&符号
    //对于第一个参数是this指针的情况，可以传递对象的地址,
    //但要注意：当函数执行时，对象的生命周期不能结束
    //
    //也可以直接传递对象, 此时会对对象进行复制
    //这说明std::bind的参数绑定采用的是值传递
    auto f1 = std::bind(&Foo::add, foo, 1, 2);
    cout << f1() << endl << endl;

    using namespace std::placeholders;
    auto f2 = std::bind(&Foo::add, foo, 1, _1);
    cout << f2(10) << endl << endl;

    auto f3 = std::bind(&Foo::add, foo, 1, _2);
    cout << f3(10, 20) << endl << endl;

    auto f4 = std::bind(&Foo::add, foo, _2, _1);
    cout << f4(10, 20) << endl << endl;

    //绑定了一个数据成员
    auto f5 = std::bind(&Foo::_data, foo);
    cout << f5() << endl;
    cout << "foo._data:" << foo._data << endl;
}

void print(int x, int & y)
{
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}

void test4()
{
    int a = 1, b = 2;
    //a,b的提前绑定， 都是采用值传递进行的
    auto f1 = std::bind(print, a, b);
    //当希望传递引用时，必须要使用引用包装器std::ref
    auto f2 = std::bind(print, a, std::ref(b));
    a = 10;
    b = 20;
    cout << "f1()" << endl;
    f1();//1, 2
    cout << "\nf2()" << endl;
    f2();
}

typedef int(*Function)(int,int);

int multiply(int x, int y)
{
    return x * y;
}

void test5()
{
    cout << "\ntest5() function" << endl;
    //普通函数可以直接给function赋值
    function<int(int,int)> f1 = add;
    f1(1, 2);

    Function f2 = multiply;//f2是一个函数指针
    f1 = f2;// 函数对象 = 函数指针
    cout << f1(3, 4) << endl;
}


int main()
{
    /* test0(); */
    /* test1(); */
    /* test2(); */
    /* test3(); */
    /* test4(); */
    test5();
    return 0;
}

